﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RWLib
{
    public class Formula
    {
        private List<Fluent> conditionsAND;                // Wyrażenie logiczne, tylko w relacji AND, równoznaczne przed De morgana wraz ze zmienną Negation
        private bool Negation = false;                     // Zmienna zaprzeczenia jak w ~( p v q)

        private bool alwaysTrue = false;

        private List<Clause> conditions;
        public List<Clause> Conditions { get { return conditions; } }

        public List<Fluent> ConditionsAND { get { return conditionsAND; } }

        public Formula(List<Fluent> conditionsAnd)
        {
            conditionsAND = conditionsAnd;
        }

        public Formula(List<Clause> conditionsCNF) {
            conditions = conditionsCNF;
        }

        public Formula() {
            alwaysTrue = true;
        }

        public List<Fluent> Fluents {
            get { 
                List<Fluent> fluents=new List<Fluent>();
                conditions.ForEach(l=>{
                    fluents.AddRange(l.Conditions);
                });
                return fluents;
            }
        }

        public int Count
        {
            get { return conditionsAND.Count(); }
        }

        public bool Holds(List<Fluent> fluents)
        {
            var value = conditionsAND.Any(condition => !fluents.Get(condition).Conflicts(condition));
            return value;
        }


        public bool Eval(List<Fluent> fluents) {
            if (alwaysTrue)
            {
                return alwaysTrue;
            }
            return !conditions.Exists(condition => !condition.Eval(fluents));
        }

        public bool Eval() {
            if (alwaysTrue) {
                return alwaysTrue;
            }
            return !conditions.Exists(condition => !condition.Eval());
        }

        public bool Conflicts(Formula c)
        {
            foreach (var condition in conditions)
            {
                if (c.Conditions.Exists(cc => cc.Conflict(condition))) {
                    return true;
                }
            }
            return false;
        }

        public bool Conflicts(List<Fluent> fluents)
        {
            var value = conditionsAND.Any(condition => fluents.Get(condition) != null && fluents.Get(condition).Conflicts(condition));
            return Negation ? !value : value;
        }

        public void Apply(List<Fluent> fluents)
        {
            foreach (var c in conditionsAND)
            {
                fluents.Get(c).Value = c.Value;
            }
        }

        public override string ToString()
        {
            if (alwaysTrue) {
                return "(true)";
            }
            var sb = new StringBuilder();
            for (int i = 0; i < conditions.Count()-1; ++i) {
                sb.Append("(");
                sb.Append(conditions[i].ToString());
                sb.Append(")");
                sb.Append(" and ");
            }
            sb.Append("(");
            sb.Append(conditions.Last().ToString());
            sb.Append(")");
            return sb.ToString();
        }
    }
}
